class TwinkleParser extends Parser;
options
{        
    buildAST=true;
    k=1;
    
}

tokens 
{
SUBPROG;
SUBPROG2;
}

program:  (activity)* main;

activity : ACTIVITY^ ID subprogram;


main: MAIN^ subprogram2;

subprogram : LBRACE! (stmts) RBRACE!
        {#subprogram = #([SUBPROG,"SUBPROG"], subprogram);};
        
subprogram2 : LBRACE! (stmts2) RBRACE!
        {#subprogram2 = #([SUBPROG2,"SUBPROG2"], subprogram2);};


//startstmt2: START^ LPAREN! ID  RPAREN!;
stmts2   :  (stmt2)*;
stmt2    :  (startstmt		   
           | showmessagestmt
           | saystmt
		   | waitForKeystmt
		   | waitstmt) SC!
		   | ifstmt 
           | whilestmt
           | subprogram2
           ;
          
           
startstmt: START^ LPAREN! ID  RPAREN!;

//#
stmts   : (stmt)*;
stmt    : (decls
		| showstmt
		| showElementstmt 	
		| showallstmt
		| showmessagestmt
		| showifpressedstmt
		| showandteststmt
		| saystmt
		| waitForKeystmt
		| waitstmt) SC!
		| loopstmt
        | subprogram
        ;

waitForKeystmt: WAITFORKEY^ LPAREN! RPAREN!;
waitstmt: WAIT^ LPAREN! NUMBER RPAREN!;

//##


showstmt: SHOW^ LPAREN! ID (COMMA! NUMBER)? RPAREN!;
//showElementstmt: SHOWELEMENT^ LPAREN! val COMMA! val COMMA! val COMMA! color COMMA! NUMBER RPAREN!;
showElementstmt: SHOWELEMENT^ LPAREN! val COMMA! val COMMA! val COMMA! val COMMA! NUMBER RPAREN!;
        

showallstmt : SHOWALL^ LPAREN! listVal COMMA! listVal COMMA! listVal COMMA!  listVal  COMMA! NUMBER RPAREN!;
//showifpressedstmt: SHOWIFPRESSED^ LPAREN! listVal COMMA! listVal COMMA! listVal COMMA! listVal COMMA! color COMMA! listVal RPAREN!;

showifpressedstmt: SHOWIFPRESSED^ LPAREN! listVal COMMA! listVal COMMA! listVal COMMA! listVal COMMA! listVal COMMA! NUMBER RPAREN!;
showandteststmt: SHOWANDTEST^ LPAREN! listVal COMMA! listVal COMMA! listVal COMMA! listVal COMMA! listVal COMMA! val  RPAREN!; 

showmessagestmt: SHOWMESSAGE^ LPAREN! val RPAREN!;

saystmt: SAY^ LPAREN! val RPAREN!;

val    //options { backtrack = true; }
         :STRING        
         |  NULL
         |  ID^  (LBRACKET! NUMBER RBRACKET!)?
          ;
valElement    //options { backtrack = true; }
         :STRING        
         |  NULL
         |  ID^  (LBRACKET! ITR RBRACKET!)?
         ;
//id_List : ID LBRACKET! NUMBER RBRACKET;
listVal  :   ID | NULL ; 
         

//val_list  :   ID_list | NULL;

 
ifstmt: IF^ LPAREN! expr RPAREN! stmt2
       (options{greedy=true;}:ELSE! stmt2)?;
       
whilestmt : WHILE^ LPAREN! expr RPAREN! subprogram2 ;

loopstmt: LOOP^ ITR! FROM! NUMBER TO! NUMBER subprogram; 


//#
expr : exp1 ((AND^ | OR^) exp1)*;
exp1 : NOT^ bool
      | bool 
      ;
bool : TRUE 
	  | FALSE
	  | ISPRESSED^ LPAREN! STRING RPAREN!
      ;

//##


// S&F to here



decls   : vardec | listdec | elementdec;

vardec   : VAR^ (ID EQUALS! STRING);
        
listdec  : LIST^ ID EQUALS! LPAREN! listarg RPAREN!;
listarg  :  STRING (COMMA! STRING)* 
         //|  color (COMMA! color)*
         ;

elementdec :  ELEMENT^ ID EQUALS! LPAREN! valElement COMMA! valElement COMMA! valElement COMMA! valElement RPAREN!;

element_var: STRING | ID | NULL;

//color : RED | BLUE | GREEN | YELLOW | ORANGE | CYAN | MAGENTA | PINK | LIGHTGREY | GREY | DARKGREY | WHITE | BLACK ;


class TwinkleLexer extends Lexer;
options 
{ 
    testLiterals =false; 
    k=2;
    charVocabulary = '\3'..'\377';
}
tokens 
{
    /* Key words  */
    MAIN = "main";
    ACTIVITY = "Activity";
    STRING = "string";
    ELEMENT = "Element";
    SHOW = "show";
    SHOWELEMENT="showElement";
    SHOWALL = "showAll";
    START = "start";
    SHOWMESSAGE = "showMessage";
    ISPRESSED = "isPressed";
    SAY = "say";
    SHOWIFPRESSED = "showIfPressed";
    SHOWANDTEST = "showAndTest";
    //#
    WAITFORKEY = "waitForKey";
    WAIT = "wait";
    //##
    
     // S&F from here
    IF = "if";
    ELSE= "else";
    WHILE = "while";
    TRUE = "true";
    FALSE = "false";
    LOOP = "loop";
    FROM = "from";
    TO = "to"; 
    ITR = "itr";
     
    // S&F from here
    NULL = "null";
    VAR = "var";
    LIST = "list";
//    RED = "RED";
//    BLUE = "BLUE";
//    GREEN = "GREEN";
//    YELLOW = "YELLOW";
//    WHITE = "WHITE";
//    BLACK = "BLACK";
//    ORANGE = "ORANGE";
//    GREY = "GREY";
//    PINK = "PINK";
//    CYAN = "CYAN";
//    MAGENTA = "MAGENTA";
//    LIGHTGREY = "LIGHT_GREY";
//   DARKGREY = "DARK_GREY"; 
}

/*  Expression */

LPAREN  : '(' ;
RPAREN  : ')' ;
LBRACE  : '{';
RBRACE  : '}';
LBRACKET : '[';
RBRACKET : ']';
COMMA   : ',';
EQUALS  : '=';
// S&F from here
AND  : "&&";
OR   : "||";
NOT  : "!";
// S&F to here


/* Identifier  */

protected DIGIT: ('0'..'9') ;

protected LETTER : ('a'..'z'|'A'..'Z');

NUMBER : (DIGIT)+;

ID  options { testLiterals =true;}
    : LETTER  ( LETTER | DIGIT | '_')* 
    ;

//protected COLOR : (RED | BLUE | GREEN | YELLOW | ORANGE | CYAN | MAGENTA | PINK | LIGHTGREY | GREY | DARKGREY | WHITE | BLACK);
//protected COLOR : ("RED" | "BLUE" | "GREEN" | "YELLOW" | "ORANGE" | "CYAN" | "MAGENTA" | "PINK" | "LIGHTGREY" | "GREY" | "DARKGREY" | "WHITE" | "BLACK");
    
STRING options { testLiterals =false;}: '"'!(~('"'|'\n'))*'"'!;

/* Others  */

COMMENT : "/*" (options{greedy=false;}:(.))* "*/" {$setType(Token.SKIP);};

SC : ';';

WS : ( ' '
| '\t'
| '\n' { newline(); }
| '\r'
) { $setType(Token.SKIP); }
; 